# -*- coding: utf-8 -*-
# @Version: Python 3.9
# @Time    : 2023/2/1 14:31
# @Author  : chenyinhua
# @File    : assert_handle.py
# @Software: PyCharm
# @Desc: 断言

# 第三方库导入
from loguru import logger
from requests import Response
import allure
# 本地应用/模块导入
from utils.data_utils.extract_data_handle import json_extractor, re_extract
from utils.report_utils.allure_handle import allure_step


@allure.step("响应断言 --> 响应数据：{response} - 预期结果：{expected}")
def assert_response(response: Response, expected: dict) -> None:
    """ 断言方法
    :param response: 实际响应对象
    :param expected: 预期响应内容，从excel中或者yaml读取、或者手动传入,格式如下：
    {
    'eq':
        {'http_code': 200, '$.user_id': '85392'},
    "in":
        {'message': "success"}
    }
    return None
    """
    logger.info("\n======================================================\n" \
                f"-------------Start：响应断言--------------------\n"
                f"响应断言预期结果：{expected}, {type(expected)}")
    if expected is None:
        return
    index = 0
    for k, v in expected.items():
        # 获取需要断言的实际结果部分
        for _k, _v in v.items():
            if _k == "http_code":
                actual = response.status_code
            else:
                if response_type(response) == "json":
                    # 如果响应数据是json格式
                    actual = json_extractor(response.json(), _k)
                else:
                    # 响应数据不是json格式
                    actual = re_extract(response.text, _k)
            index += 1
            logger.info(
                f'第{index}个响应断言 -|- 预期结果: {_k}: {_v}, {type(_v)}   {k}   实际结果: {actual}, {type(actual)}')
            allure_step(
                step_title=f'第{index}个响应断言数据---->预期结果: {_k}: {_v}, {type(_v)}   {k}   实际结果: {actual}, {type(actual)}')
            try:
                if k == "eq":  # 预期结果 = 实际结果
                    assert _v == actual
                    logger.success(f"预期结果: {_k}: {_v} ==  实际结果: {actual}, 断言成功！")
                elif k == "in":  # 实际结果 包含 预期结果
                    assert _v in actual
                    logger.success(f"预期结果: {_k}: {_v} in  实际结果: {actual}, 断言成功！")
                elif k == "gt":  # 预期结果 > 实际结果 (值应该为数值型)
                    assert _v > actual
                    logger.success(f"预期结果: {_k}: {_v} >  实际结果: {actual}, 断言成功！")
                elif k == "lt":  # 预期结果 < 实际结果 (值应该为数值型)
                    assert _v < actual
                    logger.success(f"预期结果: {_k}: {_v} <  实际结果: {actual}, 断言成功！")
                elif k == "not":  # 预期结果 != 实际结果
                    assert _v != actual
                    logger.success(f"预期结果: {_k}: {_v} !=  实际结果: {actual}, 断言成功！")
                else:
                    logger.error(f"判断关键字: {k} 错误！, 目前仅支持如下关键字：eq, in, gt, lt, not")
                    allure_step(step_title=f'判断关键字: {k} 错误！',
                                content='目前仅支持如下关键字：eq, in, gt, lt, not')
            except AssertionError:
                logger.error(
                    f"第{index}个响应断言失败 -|- 预期结果: {_k}: {_v}, {type(_v)}   {k}   实际结果: {actual}, {type(actual)}")
                allure_step(
                    step_title=f'第{index}个响应断言失败---->预期结果: {_k}: {_v}, {type(_v)}   {k}   实际结果: {actual}, {type(actual)}')
                logger.info('\n-------------End：响应断言--------------------\n' \
                            "=====================================================")
                raise AssertionError(
                    f"第{index}个响应断言失败 -|- 预期结果: {_k}: {_v}, {type(_v)}   {k}   实际结果: {actual}, {type(actual)}")

    logger.info('\n-------------End：响应断言--------------------\n' \
                "=====================================================")


def response_type(response: Response) -> str:
    """
    :param response: requests 返回
    :return: 返回响应数据类型 json或者str
    """
    try:
        response.json()
        return "json"
    except:
        return "str"
